 /*
  * can_recv.c - 接收并验证递增数的CAN程序
  * 
  * 使用方法: ./can_recv <can设备名> <can帧ID(十六进制)>
  * 例如: ./can_recv can1 123
  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>

int main(int argc, char *argv[]) {
    int s;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    int nbytes;
    unsigned long int received_value = 0;
    unsigned long int last_value = 0;
    int is_first_frame = 1;
    unsigned int can_id;
    
    // 检查命令行参数
    if (argc != 3) {
        printf("使用方法: %s <can设备名> <can帧ID(十六进制)>\n", argv[0]);
        printf("例如: %s can1 123\n", argv[0]);
        return 1;
    }
    
    // 解析CAN帧ID参数（十六进制）
    if (sscanf(argv[2], "%x", &can_id) != 1) {
        printf("错误: CAN帧ID必须是有效的十六进制数\n");
        return 1;
    }
    
    // 创建socket
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("创建socket失败");
        return 1;
    }
    
    // 指定CAN设备
    strcpy(ifr.ifr_name, argv[1]);
    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
        perror("获取接口索引失败");
        close(s);
        return 1;
    }
    
    // 绑定socket到CAN接口
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("绑定socket失败");
        close(s);
        return 1;
    }
    
    // 设置过滤器，只接收指定ID的帧
    struct can_filter rfilter[1];
    rfilter[0].can_id = can_id;
    rfilter[0].can_mask = CAN_SFF_MASK;
    if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)) < 0) {
        perror("设置过滤器失败");
        close(s);
        return 1;
    }
    
    printf("开始从 %s 接收数据，CAN帧ID: 0x%X...\n", argv[1], can_id);
    printf("按Ctrl+C停止\n");
    
    // 循环接收数据
    while (1) {
        nbytes = read(s, &frame, sizeof(struct can_frame));
        if (nbytes < 0) {
            perror("读取CAN帧失败");
            close(s);
            return 1;
        }
        
        // 检查是否是我们期望的CAN帧ID
        if (frame.can_id != can_id) {
            printf("接收到意外的CAN帧ID: 0x%X\n", frame.can_id);
            continue;
        }
        
        // 从CAN帧数据中提取值
        received_value = 0;
        for (int i = 0; i < 8; i++) {
            received_value = (received_value << 8) | frame.data[i];
        }
        
        // 检查是否为递增数
        if (is_first_frame) {
            printf("接收到初始值: %llu\n", (unsigned long long)received_value);
            is_first_frame = 0;
        } else {
            if (received_value == last_value + 1) {
                printf("\r接收到递增值: %llu", (unsigned long long)received_value);
            } else {
                printf("\n错误: 接收到非递增值! 上一个值: %llu, 当前值: %llu\n", 
                       (unsigned long long)last_value, (unsigned long long)received_value);
                // break;
            }
        }
        
        last_value = received_value;
        fflush(stdout);
    }
    
    // 关闭socket
    close(s);
    return 0;
}
